<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>智能自动化测试平台</title>
    <style>
        /* 基础样式 */
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: "Microsoft YaHei", sans-serif;
        }
        body {
            background-color: #f5f7fa;
            padding: 20px;
        }
        .container {
            max-width: 1200px;
            margin: 0 auto;
        }
        h1 {
            color: #333;
            text-align: center;
            margin-bottom: 30px;
        }
        .card {
            background: white;
            border-radius: 8px;
            box-shadow: 0 2px 8px rgba(0,0,0,0.1);
            padding: 20px;
            margin-bottom: 20px;
        }
        .card h2 {
            color: #409eff;
            margin-bottom: 15px;
            font-size: 18px;
            border-left: 3px solid #409eff;
            padding-left: 10px;
        }
        .btn {
            background-color: #409eff;
            color: white;
            border: none;
            padding: 8px 16px;
            border-radius: 4px;
            cursor: pointer;
            font-size: 14px;
        }
        .btn:hover {
            background-color: #66b1ff;
        }
        .btn-batch {
            background-color: #1890ff; /* 批量操作按钮用更深的蓝色区分 */
        }
        .btn-batch:hover {
            background-color: #40a9ff;
        }
        .tips {
            color: #666;
            font-size: 14px;
            margin: 10px 0;
            line-height: 1.5;
        }
        .success {
            color: #52c41a;
        }
        .error {
            color: #f5222d;
        }

        /* 上传区域样式 */
        .upload-area {
            border: 2px dashed #ddd;
            border-radius: 6px;
            padding: 30px;
            text-align: center;
            margin-bottom: 15px;
        }
        #fileInput {
            display: none;
        }
        .upload-btn {
            margin-top: 10px;
        }

        /* 表格样式 */
        table {
            width: 100%;
            border-collapse: collapse;
            margin-top: 10px;
            font-size: 14px;
        }
        th, td {
            border: 1px solid #eee;
            padding: 10px;
            text-align: left;
        }
        th {
            background-color: #f9f9f9;
            color: #666;
        }
        tr:hover {
            background-color: #f5f5f5;
        }
        .action-btn {
            padding: 4px 8px;
            font-size: 12px;
            margin-right: 5px;
        }
    </style>
</head>
<body>
<div class="container">
    <h1>智能自动化测试平台</h1>

    <!-- 1. 文档上传区域 -->
    <div class="card">
        <h2>1. 接口文档上传（Swagger/OpenAPI）</h2>
        <div class="upload-area">
            <p>点击选择文件或拖放至此处</p>
            <input type="file" id="fileInput" accept=".json,.yaml,.yml">
            <button class="btn" onclick="document.getElementById('fileInput').click()">选择文件</button>
            <button class="btn upload-btn" onclick="uploadDoc()">上传并解析</button>
            <p id="uploadMsg" class="tips"></p>
        </div>
        <p class="tips">支持格式：.json（Swagger）、.yaml/.yml（OpenAPI），文件大小不超过10MB</p>
    </div>

    <!-- 2. 接口列表区域（新增基础URL输入） -->
    <div class="card">
        <h2>2. 已解析接口列表</h2>
        <!-- 新增：被测试项目基础URL输入 -->
        <div style="margin-bottom: 15px;">
            <label for="baseUrlInput" style="margin-right: 10px;">被测试项目基础URL：</label>
            <input
                    type="text"
                    id="baseUrlInput"
                    placeholder="如 http://localhost:8090"
                    style="width: 300px; padding: 6px; border: 1px solid #ddd; border-radius: 4px;"
            >
            <button class="btn" onclick="saveBaseUrl()">保存</button>
            <p class="tips" id="baseUrlMsg" style="margin-top: 5px;"></p>
        </div>
        <!-- 原按钮和表格 -->
        <button class="btn" onclick="loadApiList()">刷新接口列表</button>
        <p class="tips" id="apiListMsg"></p>
        <table id="apiTable">
            <thead>
            <tr>
                <th>ID</th>
                <th>服务名称</th>
                <th>接口路径</th>
                <th>请求方法</th>
                <th>操作</th>
            </tr>
            </thead>
            <tbody>
            <!-- 接口数据将通过JS动态加载 -->
            <tr><td colspan="5" style="text-align:center">请先上传接口文档</td></tr>
            </tbody>
        </table>
    </div>

    <!-- 3. 测试用例区域 -->
    <div class="card">
        <h2>3. 测试用例列表</h2>
        <button class="btn" onclick="loadTestCaseList()">刷新用例列表</button>
        <p class="tips" id="caseListMsg"></p>
        <table id="caseTable">
            <thead>
            <tr>
                <th>用例ID</th>
                <th>关联接口</th>
                <th>用例名称</th>
                <th>优先级</th>
                <th>状态</th>
                <th>操作</th>
            </tr>
            </thead>
            <tbody>
            <!-- 用例数据将通过JS动态加载 -->
            <tr><td colspan="6" style="text-align:center">暂无测试用例</td></tr>
            </tbody>
        </table>
    </div>

    <!-- 4. 测试结果区域 -->
    <div class="card">
        <h2>4. 测试执行结果</h2>
        <button class="btn" onclick="loadTestResult()">刷新结果列表</button>
        <p class="tips" id="resultMsg"></p>
        <table id="resultTable">
            <thead>
            <tr>
                <th>结果ID</th>
                <th>用例ID</th>
                <th>执行时间</th>
                <th>是否通过</th>
                <th>耗时(ms)</th>
                <th>失败原因</th>
            </tr>
            </thead>
            <tbody>
            <!-- 结果数据将通过JS动态加载 -->
            <tr><td colspan="6" style="text-align:center">暂无测试结果</td></tr>
            </tbody>
        </table>
    </div>
</div>

<script>
    // 后端API基础路径（根据实际部署地址修改）
    const BASE_API = "http://localhost:8080/api";

    // 新增：初始化基础URL（从localStorage读取）
    function initBaseUrl() {
        const savedUrl = localStorage.getItem('testedProjectBaseUrl');
        if (savedUrl) {
            document.getElementById('baseUrlInput').value = savedUrl;
            showMsg('baseUrlMsg', '已加载保存的基础URL', 'tips');
        } else {
            // 默认值（可选）
            document.getElementById('baseUrlInput').value = 'http://localhost:8090';
        }
    }

    // 新增：保存基础URL到localStorage
    function saveBaseUrl() {
        const baseUrl = document.getElementById('baseUrlInput').value.trim();
        if (!baseUrl) {
            showMsg('baseUrlMsg', '基础URL不能为空', 'error');
            return;
        }
        // 简单验证URL格式（含http/https）
        if (!baseUrl.startsWith('http://') && !baseUrl.startsWith('https://')) {
            showMsg('baseUrlMsg', 'URL需以 http:// 或 https:// 开头', 'error');
            return;
        }
        localStorage.setItem('testedProjectBaseUrl', baseUrl);
        showMsg('baseUrlMsg', '基础URL保存成功', 'success');
    }

    // 1. 上传接口文档（不变）
    function uploadDoc() {
        const fileInput = document.getElementById('fileInput');
        const file = fileInput.files[0];
        if (!file) {
            showMsg('uploadMsg', '请先选择文件', 'error');
            return;
        }

        // 验证文件格式
        const allowedTypes = ['.json', '.yaml', '.yml'];
        const fileName = file.name;
        const fileExt = fileName.substring(fileName.lastIndexOf('.'));
        if (!allowedTypes.includes(fileExt)) {
            showMsg('uploadMsg', '仅支持 .json, .yaml, .yml 格式', 'error');
            return;
        }

        // 构建FormData
        const formData = new FormData();
        formData.append('file', file);

        // 调用后端接口
        fetch(`${BASE_API}/docs/upload`, {
            method: 'POST',
            body: formData
        })
            .then(response => response.text())
            .then(data => {
                showMsg('uploadMsg', data, 'success');
                fileInput.value = ''; // 清空文件选择
                loadApiList(); // 自动刷新接口列表
            })
            .catch(error => {
                showMsg('uploadMsg', '上传失败：' + error.message, 'error');
            });
    }

    // 2. 加载接口列表（修改：操作列添加“一键测试”按钮）
    function loadApiList() {
        fetch(`${BASE_API}/docs/list`)
            .then(response => {
                if (!response.ok) throw new Error('接口列表获取失败');
                return response.json();
            })
            .then(apis => {
                const tableBody = document.querySelector('#apiTable tbody');
                if (apis.length === 0) {
                    tableBody.innerHTML = '<tr><td colspan="5" style="text-align:center">暂无接口数据</td></tr>';
                    showMsg('apiListMsg', '接口列表为空', 'tips');
                    return;
                }

                // 动态生成表格内容（新增“一键测试”按钮）
                let html = '';
                apis.forEach(api => {
                    html += `
                    <tr>
                        <td>${api.id}</td>
                        <td>${api.serviceName || '-'}</td>
                        <td>${api.path}</td>
                        <td>${api.method}</td>
                        <td>
                            <button class="btn action-btn" onclick="generateTestCase(${api.id})">生成用例</button>
                            <button class="btn action-btn btn-batch" onclick="batchRunByApiId(${api.id})">一键测试</button>
                        </td>
                    </tr>`;
                });
                tableBody.innerHTML = html;
                showMsg('apiListMsg', `共加载 ${apis.length} 个接口`, 'success');
            })
            .catch(error => {
                showMsg('apiListMsg', error.message, 'error');
            });
    }

    // 3. 生成测试用例（不变）
    function generateTestCase(apiId) {
        showMsg('caseListMsg', '正在生成用例...', 'tips');
        fetch(`${BASE_API}/cases/generate?apiId=${apiId}`, { method: 'POST' })
            .then(response => response.text())
            .then(data => {
                showMsg('caseListMsg', data, 'success');
                loadTestCaseList(); // 自动刷新用例列表
            })
            .catch(error => {
                showMsg('caseListMsg', '生成失败：' + error.message, 'error');
            });
    }

    // 4. 加载测试用例列表（不变）
    function loadTestCaseList() {
        fetch(`${BASE_API}/cases/list`)
            .then(response => {
                if (!response.ok) throw new Error('用例列表获取失败');
                return response.json();
            })
            .then(cases => {
                const tableBody = document.querySelector('#caseTable tbody');
                if (cases.length === 0) {
                    tableBody.innerHTML = '<tr><td colspan="6" style="text-align:center">暂无测试用例</td></tr>';
                    showMsg('caseListMsg', '用例列表为空', 'tips');
                    return;
                }

                // 动态生成表格内容
                let html = '';
                cases.forEach(caseItem => {
                    const priorityMap = {1: '高', 2: '中', 3: '低'};
                    const statusMap = {0: '未执行', 1: '已执行', 2: '废弃'};
                    html += `
                    <tr>
                        <td>${caseItem.id}</td>
                        <td>${caseItem.apiId}</td>
                        <td>${caseItem.caseName}</td>
                        <td>${priorityMap[caseItem.priority]}</td>
                        <td>${statusMap[caseItem.status]}</td>
                        <td>
                            <button class="btn action-btn" onclick="runTestCase(${caseItem.id})">执行</button>
                        </td>
                    </tr>`;
                });
                tableBody.innerHTML = html;
                showMsg('caseListMsg', `共加载 ${cases.length} 个用例`, 'success');
            })
            .catch(error => {
                showMsg('caseListMsg', error.message, 'error');
            });
    }

    // 修改：执行单个用例时传递baseUrl
    function runTestCase(caseId) {
        const baseUrl = document.getElementById('baseUrlInput').value.trim();
        if (!baseUrl) {
            showMsg('resultMsg', '请先填写并保存被测试项目基础URL', 'error');
            return;
        }
        showMsg('resultMsg', '正在执行用例...', 'tips');
        // 用POST请求体传递baseUrl（避免URL拼接特殊字符问题）
        fetch(`${BASE_API}/results/run/${caseId}`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({ baseUrl: baseUrl })
        })
            .then(response => response.text())
            .then(data => {
                showMsg('resultMsg', data, 'success');
                loadTestResult();
            })
            .catch(error => {
                showMsg('resultMsg', '执行失败：' + error.message, 'error');
            });
    }

    // 修改：批量执行用例时传递baseUrl
    function batchRunByApiId(apiId) {
        const baseUrl = document.getElementById('baseUrlInput').value.trim();
        if (!baseUrl) {
            showMsg('resultMsg', '请先填写并保存被测试项目基础URL', 'error');
            return;
        }
        showMsg('resultMsg', `正在批量执行接口[${apiId}]的所有用例...`, 'tips');
        fetch(`${BASE_API}/results/run/batch/${apiId}`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({ baseUrl: baseUrl })
        })
            .then(response => response.text())
            .then(data => {
                showMsg('resultMsg', data, 'success');
                loadTestResult();
                loadTestCaseList();
            })
            .catch(error => {
                showMsg('resultMsg', '批量执行失败：' + error.message, 'error');
            });
    }



    // 7. 加载测试结果（不变）
    function loadTestResult() {
        fetch(`${BASE_API}/results/list`)
            .then(response => {
                if (!response.ok) throw new Error('结果列表获取失败');
                return response.json();
            })
            .then(results => {
                const tableBody = document.querySelector('#resultTable tbody');
                if (results.length === 0) {
                    tableBody.innerHTML = '<tr><td colspan="6" style="text-align:center">暂无测试结果</td></tr>';
                    showMsg('resultMsg', '结果列表为空', 'tips');
                    return;
                }

                // 动态生成表格内容
                let html = '';
                results.forEach(result => {
                    const isPass = result.isPass === 1 ? '通过' : '失败';
                    const passClass = result.isPass === 1 ? 'success' : 'error';
                    html += `
                    <tr>
                        <td>${result.id}</td>
                        <td>${result.caseId}</td>
                        <td>${formatTime(result.executeTime)}</td>
                        <td class="${passClass}">${isPass}</td>
                        <td>${result.duration || '-'}</td>
                        <td>${result.failReason || '-'}</td>
                    </tr>`;
                });
                tableBody.innerHTML = html;
                showMsg('resultMsg', `共加载 ${results.length} 条结果`, 'success');
            })
            .catch(error => {
                showMsg('resultMsg', error.message, 'error');
            });
    }

    // 工具函数：显示提示消息（不变）
    function showMsg(elementId, text, type = 'tips') {
        const element = document.getElementById(elementId);
        element.textContent = text;
        element.className = type; // 切换样式类（success/error/tips）
    }

    // 工具函数：格式化时间（不变）
    function formatTime(timeStr) {
        if (!timeStr) return '-';
        // 假设后端返回格式为 ISO 时间（如 2023-10-01T12:00:00）
        return new Date(timeStr).toLocaleString();
    }

    // 页面加载时初始化基础URL
    window.onload = function() {
        initBaseUrl(); // 新增
        loadApiList();
    };
</script>
</body>
</html>